home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / SNIP9_91.ARJ / MORSE.C < prev    next >
C/C++ Source or Header  |  1991-09-05  |  8KB  |  239 lines

  1. /*
  2. **   <<< Morse Code Functions >>>
  3. ** 
  4. ** Written by Michael M. Dodd, N4CF, and placed in the public domain.
  5. ** 
  6. ** The morse() function transmits a string in Morse code on the IBM PC's
  7. ** speaker.  The speed is set by a program constant (UNIT_TIME).
  8. ** 
  9. ** There are several other functions in this file, all used by morse(),
  10. ** and defined ahead of morse() for convenience.
  11. ** 
  12. ** The main() function at the end of the file is a test program to send
  13. ** the command-line argument string in morse code.  Enclose multiple
  14. ** words in quotes.  Example:  morse "hello, world"
  15. ** 
  16. ** These functions have been compiled and tested in the Small and Large
  17. ** memory models using Microsoft C 6.00a.
  18. **
  19. ** Modified for ZTC++, TC++, & BC++ by Bob Stout
  20. */
  21.  
  22. #include <stdio.h>
  23. #include <dos.h>
  24. #include <conio.h>
  25. #include <ctype.h>
  26.  
  27. /*
  28. ** These functions turn on and off the CW tone on the PC's speaker.  The
  29. ** frequency is specified by the freq argument.
  30. ** IMPORTANT!  These functions are highly IBM PC-specific!
  31. */
  32.  
  33. #define CLK_FREQ (1193180L)
  34. #define PIO (0x61)
  35. #define CTC_CMD (0x43)
  36. #define CTC_DATA (0x42)
  37. #define SETUP (0xB6)
  38. #define TONE_ON (0x03)
  39. #define TONE_OFF (0xFC)
  40.  
  41. void note_on (int freq)        /* Turn on the tone.  */
  42. {
  43.       int divisor ;
  44.       int pio_word ;
  45.  
  46.       divisor = (int)(CLK_FREQ / (long)(freq)) ;
  47.       outp (CTC_CMD, SETUP) ;
  48.       outp (CTC_DATA, divisor & 0xFF) ;
  49.       outp (CTC_DATA, divisor >> 8) ;
  50.       pio_word = inp (PIO) ;
  51.       outp (PIO, pio_word | TONE_ON) ;
  52. }
  53.  
  54. void note_off (void)           /* Turn off the tone.  */
  55. {
  56.       int pio_word ;
  57.  
  58.       pio_word = inp (PIO) ;
  59.       outp (PIO, pio_word & TONE_OFF) ;
  60. }
  61.  
  62. /*
  63. ** These functions implement a timing-loop delay.  Because the PC's
  64. ** internal clock is too coarse for accurate CW timing, the pause()
  65. ** function uses a simple software loop to produce a delay.
  66. ** 
  67. ** To minimize the effects of CPU clock speed, the calib() function
  68. ** returns a number which represents a rough index of the clock speed
  69. ** with relation to the standard IBM PC (this is very approximate).
  70. ** 
  71. ** Calibration is performed only once, when the static fudge_factor is
  72. ** zero.  Thereafter, the contents of fudge_factor are used to form a
  73. ** delay value.
  74. ** 
  75. ** IMPORTANT!  These functions are highly IBM PC-specific!
  76. */
  77.  
  78. unsigned int calib (void)
  79. {
  80.       unsigned int far *timerLow = (unsigned int far *)(0x046c) ;
  81.       unsigned int lastTime ;
  82.       unsigned int iter ;
  83.  
  84.       for (lastTime = *timerLow; lastTime == *timerLow;)
  85.             ;
  86.  
  87.       for (iter = 0, lastTime = *timerLow; lastTime == *timerLow; iter++)
  88.             ;
  89. #if   defined(__ZTC__)
  90.       return ((unsigned int)((125L * ((long)(iter)) + 50L) / 2300L)) ;
  91. #elif defined(__TURBOC__)
  92.       return ((unsigned int)((77L * ((long)(iter)) + 50L) / 2300L)) ;
  93. #else /* assume MSC */
  94.       return ((unsigned int)((100L * ((long)(iter)) + 50L) / 2300L)) ;
  95. #endif
  96. }
  97.  
  98. void pause (unsigned int amount)
  99. {
  100.       static unsigned int fudge_factor = 0 ;
  101.       unsigned long ul ;
  102.  
  103.       if (fudge_factor == 0)       /* Calibrate the speed.  */
  104.             fudge_factor = calib () ;
  105.  
  106.       ul = (unsigned long)(amount) * (long)(fudge_factor) ;
  107.       while (ul--)                 /* Delay.  */
  108.             ;
  109. }
  110.  
  111. /*
  112. ** These functions transmit a dot, a dash, a letter space, and a
  113. ** word space.
  114. ** 
  115. ** Note that a single unit space is automatically transmitted after
  116. ** each dot or dash, so the ltr_space() function produces only a
  117. ** two-unit pause.
  118. ** 
  119. ** Also, the word_space() function produces only a four-unit pause
  120. ** because the three-unit letter space has already occurred following
  121. ** the previous letter.
  122. */
  123.  
  124. #define SPACE_MASK (1 << 15)
  125. #define BIT_MASK (0xfe)
  126. #define UNIT_TIME (18)
  127. #define FREQUENCY (1500)
  128.  
  129. void send_dot (void)           /* Send a dot and a space.  */
  130. {
  131.       note_on (FREQUENCY) ;
  132.       pause (UNIT_TIME) ;
  133.       note_off () ;
  134.       pause (UNIT_TIME) ;
  135. }
  136.  
  137. void send_dash (void)          /* Send a dash and a space.  */
  138. {
  139.       note_on (FREQUENCY) ;
  140.       pause (UNIT_TIME * 3) ;
  141.       note_off () ;
  142.       pause (UNIT_TIME) ;
  143. }
  144.  
  145. void ltr_space (void)          /* Produce a letter space.  */
  146. {
  147.       pause (UNIT_TIME * 2) ;
  148. }
  149.  
  150. void word_space (void)         /* Produce a word space.  */
  151. {
  152.       pause (UNIT_TIME * 4) ;
  153. }
  154.  
  155.  
  156. /*
  157. ** MORSE () - Transmit a string in Morse code
  158. ** 
  159. ** This function transmits the string pointed to by the cp argument in
  160. ** Morse code on the PC's speaker.  The speed is set by the UNIT_TIME
  161. ** constant.
  162. ** 
  163. ** A static table translates from ASCII to Morse code.  Each entry is
  164. ** an unsigned integer, where a zero represents a dot and a one
  165. ** represents a dash.  No more than 14 bits may be used.  Setting bit
  166. ** 15 produces a word space, regardless of any other pattern.
  167. ** 
  168. ** The Morse code pattern is taken from bit 0, and is shifted right
  169. ** each time an element is sent.  A special "marker bit" follows the
  170. ** complete Morse pattern.  This marker bit is tested before
  171. ** transmitting each bit; if there are no 1's in bits 1..15, the
  172. ** complete character has been sent.
  173. ** 
  174. ** For example, an "L" would be 0000000000010010, with bit zero
  175. ** containing the first dot, bit one the dash, etc.  The marker
  176. ** bit is in bit 4.
  177. */
  178.  
  179. void morse (char *cp)
  180. {  /*--- MORSE CODE FUNCTION ---*/
  181.  
  182.       unsigned int c ;
  183.       static unsigned int codes [64] = {
  184.             SPACE_MASK,                      /* Entry 0 = space (0x20)  */
  185.             0, 0, 0, 0, 0, 0, 0, 0,          /* ! " # $  % & " (  */
  186.             0, 0, 0, 115, 49, 106, 41,       /* ) * + , - . /     */
  187.             63, 62, 60, 56, 48, 32, 33, 35,  /* 0 1 2 3 4 5 6 7   */
  188.             39, 47, 0, 0, 0, 0, 0, 76,       /* 8 9 : ; < = > ?   */
  189.             0, 6, 17, 21, 9, 2, 20, 11,      /* @ A B C D E F G   */
  190.             16, 4, 30, 13, 18, 7, 5, 15,     /* H I J K L M N O   */
  191.             22, 27, 10, 8, 3, 12, 24, 14,    /* P Q R S T U V W   */
  192.             25, 29, 19                       /* X Y Z  */
  193.             } ;
  194.  
  195.       pause (0) ;                  /* Calibrate pause() function.  */
  196.  
  197.       while ((c = *cp++) != '\0')
  198.       {  /*--- TRANSMIT COMPLETE STRING ---*/
  199.  
  200.             c = toupper (c) ;          /* No lower-case Morse characters.  */
  201.             c -= ' ' ;                 /* Adjust for zero-based table.  */
  202.  
  203.             if (c < 0 || c > 58)       /* If out of range, ignore it.  */
  204.                   continue ;
  205.  
  206.             c = codes[c] ;             /* Look up Morse pattern from table. */
  207.  
  208.             if (c & SPACE_MASK)        /* If the space bit is set..  */
  209.             {                          /* ..send a word space and go on.  */
  210.                   word_space () ;
  211.                   continue ;
  212.             }
  213.  
  214.             while (c & BIT_MASK)       /* Transmit one character.  */
  215.             {  /*--- TRANSMIT EACH BIT ---*/
  216.                   if (c & 1)
  217.                         send_dash () ;
  218.                   else  send_dot () ;
  219.  
  220.                   c >>= 1 ;
  221.             }  /*--- TRANSMIT EACH BIT ---*/
  222.  
  223.             ltr_space () ;             /* Send a space following character. */
  224.  
  225.       }  /*--- TRANSMIT COMPLETE STRING ---*/
  226.  
  227. }  /*--- MORSE CODE FUNCTION ---*/
  228.  
  229.  
  230. /*
  231. ** This is the test program, which transmits argv[1] in Morse code.
  232. */
  233.  
  234. void main (int argc, char *argv[])
  235. {
  236.       if (argc > 1)
  237.             morse (argv[1]) ;
  238. }
  239.